Load libraries

# install.packages(c("bioacoustics", "tuneR", "seewave", "dplyr", "tidyverse", "lubridate", "tools", "ggplot2", "ggpmisc", "plotly", "stringr", "monitoR", "pbapply", "foreach", "doParallel", "R.utils"), type="binary")
library(bioacoustics)
library(tuneR)
library(seewave)
library(dplyr)
library(tidyverse)
library(lubridate)
library(tools)
library(ggplot2)
library(ggpmisc)
library(plotly)
library(stringr)
library(foreach)
library(doParallel)
library(R.utils)
ymd_hms = function(dt) {
  lubridate::ymd_hms(dt, tz="Pacific/Auckland")
}
dmy_hms = function(dt) {
  lubridate::dmy_hms(dt, tz="Pacific/Auckland")
}
options(stringsAsFactors = FALSE)

Load RFID log files

files = list.files("data/2019 RFID", pattern = "*.TXT$", recursive = TRUE, full.names=TRUE)
csvs = lapply(files, function(path) {
  csv = read.csv(path, header=FALSE, col.names = c("year", "month", "day", "hour","minute_sec", "id", "ext", "int", "msg"))
  csv$site = strsplit(strsplit(path, "/")[[1]][4], "_")[[1]][1]
  csv
})
rfid = do.call(rbind, csvs)
rfid$datetime = paste0(rfid$year, "-", rfid$month, "-", rfid$day, " ", rfid$hour, ":", rfid$minute_sec)
rfid$datetime = ymd_hms(rfid$datetime)
ggplot(rfid, aes(datetime)) +
  geom_freqpoly(binwidth = 60 * 60)

Reference spectrograms for playback files

html_tag_audio <- function(file, type = c("wav")) {
  type <- match.arg(type)
  htmltools::tags$h3(
    basename(file),
    htmltools::tags$audio(
      controls = "",
      htmltools::tags$source(
        src = file,
        type = glue::glue("audio/{type}", type = type)
      )
    )
  )
}
files = Sys.glob("./clips/PB*.wav")
PB_wavs = lapply(files, function(f) {
  wav = read_audio(f)
  wav_length = round(length(wav) / wav@samp.rate, 2)
  spectro(wav, main=paste0(basename(f), " ", wav_length, "s"), osc=TRUE)
  print(html_tag_audio(f))
  data.frame(filename=basename(f), wav_length)
})

PB0009zp.wav

PB0014zp.wav

PB0023.wav

PB0024.wav

PBB11up.wav

PB_wavs = do.call(rbind, PB_wavs)

Build a reference dataframe showing which wave files correspond to which times

read_BAR_metadata = function(files) {
  library(pbapply)
  df = pblapply(files, function(f) {
    bits = strsplit(basename(f), "_")[[1]]
    start = ymd_hms(paste(bits[2], bits[3]))
    site = strsplit(f, "/")[[1]][4]
    try({
      wav_header = readWave(f, header=TRUE)
      duration = wav_header$samples / wav_header$sample.rate
      end = start + duration
      return(data.frame(filename = f, base_filename = basename(f), site = site, start = start, end = end, samples = wav_header$samples, sr = wav_header$sample.rate, duration=duration, interval = interval(start, end)))
    })
    NULL
  })
  df = do.call(rbind, df)
  df
}
if (file.exists("misc/BAR_timespans.csv")) {
  df = read.csv("misc/BAR_timespans.csv")
  df$start = ymd_hms(df$start)
  df$end = ymd_hms(df$end)
  df$interval = interval(df$start, df$end)
} else {
  files = list.files("data/2019 BAR recordings", pattern = "*.wav$", recursive = TRUE, full.names=TRUE)
  df = read_BAR_metadata(files)
  write.csv(df, "misc/BAR_timespans.csv", row.names = FALSE)
}
df[c("site", "interval")]

Select a few playback entries to check

PB_to_check = "PB0023.wav"
site_to_check = "NNK30"
filtered_rfid = filter(rfid, msg == PB_to_check & site == site_to_check)
filtered_df = filter(df, site == site_to_check)
filtered_rfid$corrected_datetime = filtered_rfid$datetime
filtered_rfid$match = lapply(1:nrow(filtered_rfid), function(i) {
  dt = filtered_rfid$corrected_datetime[i]
  site = filtered_rfid$site[i]
  indices = which(dt %within% filtered_df$interval)
  if (length(indices) == 0) indices = NA
  indices
})
print(paste("There are", nrow(filtered_rfid), PB_to_check, "playbacks, of which", sum(!is.na(filtered_rfid$match)), "have recordings"))
[1] "There are 307 PB0023.wav playbacks, of which 48 have recordings"
# A few randomly
datetimes_to_check = sort(sample(filtered_rfid$corrected_datetime[!is.na(filtered_rfid$match)], 5))
# Ones from the 13th
#datetimes_to_check = filtered_rfid$corrected_datetime[!is.na(filtered_rfid$match) & filtered_rfid$datetime > ymd_hms("2019-11-20 00:00:00") & filtered_rfid$datetime < ymd_hms("2019-11-20 23:59:59")]
#datetimes_to_check = filtered_rfid$corrected_datetime[!is.na(filtered_rfid$match) & filtered_rfid$corrected_datetime %within% interval(ymd_hms("2019-12-13 16:45:00"), ymd_hms("2019-12-13 17:13:00"))]
print(datetimes_to_check)
[1] "2019-12-13 15:37:01 NZDT" "2019-12-13 17:31:15 NZDT" "2019-12-13 17:57:57 NZDT" "2019-12-14 08:12:44 NZDT"
[5] "2019-12-14 08:25:41 NZDT"
#dt = ymd_hms("2019-12-13 16:45:04")
setWavPlayer("play") # OS dependent
checked_clips = lapply(datetimes_to_check, function(dt) {
  match = filtered_rfid$match[filtered_rfid$corrected_datetime == dt][[1]]
  f = filtered_df$filename[match]
  clip_start = time_length(dt - filtered_df$start[match], unit = "seconds")
  clip_end = clip_start + 1
  print(paste(f, dt, clip_start, clip_end))
  wav = read_audio(f, from = clip_start, to = clip_end)
  spectro(wav, main=dt, osc=TRUE)
  play(wav)
  wav
})
[1] "data/2019 BAR recordings/NNK Kamahi nests/NNK30/NNK30_20191213_STUDY [-39.1072 176.8183]/NNK30_20191213_144041_SunriseToSunset [-39.1072 176.8183].wav 2019-12-13 15:37:01 3380 3381"
play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [     -|-     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [     =|=     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNK Kamahi nests/NNK30/NNK30_20191213_STUDY [-39.1072 176.8183]/NNK30_20191213_164039_SunriseToSunset [-39.1072 176.8183].wav 2019-12-13 17:31:15 3036 3037"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNK Kamahi nests/NNK30/NNK30_20191213_STUDY [-39.1072 176.8183]/NNK30_20191213_164039_SunriseToSunset [-39.1072 176.8183].wav 2019-12-13 17:57:57 4638 4639"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNK Kamahi nests/NNK30/NNK30_20191214_STUDY [-39.1072 176.8183]/NNK30_20191214_064038_SunriseToSunset [-39.1072 176.8183].wav 2019-12-14 08:12:44 5526 5527"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNK Kamahi nests/NNK30/NNK30_20191214_STUDY [-39.1072 176.8183]/NNK30_20191214_064038_SunriseToSunset [-39.1072 176.8183].wav 2019-12-14 08:25:41 6303 6304"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [     -|-     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.

Write out a csv of approx positions of PB events per wave file

if (file.exists("misc/approx_offsets.csv")) {
  approx_offsets = read.csv("misc/approx_offsets.csv")
} else {
  filtered_rfid = rfid[str_extract(rfid$msg, "^.{2}") == "PB",]
  approx_offsets = lapply(1:nrow(df), function(i) {
    matched_events = filtered_rfid[filtered_rfid$site == df$site[i] & filtered_rfid$datetime %within% df$interval[i],]
    if (nrow(matched_events) == 0) {
      return(NULL)
    }
    if (nrow(matched_events) > 10) {
      matched_events = sample_n(matched_events, 10)
    }
    offsets = time_length(matched_events$datetime - df$start[i])
    data.frame(filename = df$filename[i], offset = offsets, site = matched_events$site, pb = matched_events$msg, datetime = matched_events$datetime)
  })
  approx_offsets = do.call(rbind, approx_offsets)
  write.csv(approx_offsets, "misc/approx_offsets.csv", row.names = FALSE)
}

Compare annotations with nearest RFID log

annotations = lapply(list.files("misc", "*.txt", full.names=TRUE), function(f) {
  if (str_detect(f, "ZOOM")) {
    return(NULL)
  } else if (str_detect(f, "selections")) {
    x = read.table(f, sep="\t", header=TRUE)
    x$datetime = ymd_hms(paste(x$Begin.Date, x$Begin.Clock.Time))
    x = x[c("Begin.Time..s.", "End.Time..s.", "Individual.ID", "Nest.ID", "datetime")]
  } else {
    x = read.table(f, col.names = c("Begin.Time..s.", "End.Time..s.", "Individual.ID"))[c(TRUE, FALSE),]
    x$Begin.Time..s. = as.numeric(x$Begin.Time..s.)
    x$End.Time..s. = as.numeric(x$Begin.Time..s.)
    x$Nest.ID = strsplit(basename(f), "_")[[1]][1]
    x$datetime = df$start[df$base_filename == str_replace(basename(f), ".txt", ".wav")] + x$Begin.Time..s.
  }
  x$filename = paste0(str_replace(basename(f), ".Band.Limited.Energy.Detector.selections.txt|.txt", ""), ".wav")
  x
})
annotations = do.call(rbind, annotations)
annotations$offset = rep(NA, nrow(annotations))
annotations$Individual.ID[annotations$Individual.ID == "PB0009" | annotations$Individual.ID == "PB009"] = "PB0009zp"
annotations$Nest.ID[annotations$Nest.ID == "NKN31"] = "NNK31"
for (i in 1:nrow(annotations)) {
  if (substring(annotations$Individual.ID[i], 0, 2) == "PB") {
    filtered_rfid = filter(rfid, annotations$Nest.ID[i] == site & msg == paste0(annotations$Individual.ID[i], ".wav"))
    matched_rec_start = df$start[df$site == annotations$Nest.ID[i] & annotations$datetime[i] %within% df$interval]
    diffs = time_length(filtered_rfid$datetime - annotations$datetime[i])
    min_i = which.min(abs(diffs))
    offset = diffs[min_i]
    if (length(offset) == 1) {
      annotations$offset[i] = offset
    }
  }
}
approx_offsets = read_excel("misc/approx_offsets.xlsx")

-
/
                                                                                                                        
New names:
* `Time offset observed by IGM` -> `Time offset observed by IGM...5`
* `Time offset observed by IGM` -> `Time offset observed by IGM...9`
names(approx_offsets) = c("filename", "guide_start", NA, NA, "Begin.Time..s.", "Nest.ID", "Individual.ID", "datetime", NA)
annotations = within(annotations, rm(End.Time..s.))
approx_offsets$offset = approx_offsets$guide_start - approx_offsets$Begin.Time..s.
approx_offsets$filename = basename(approx_offsets$filename)
approx_offsets$Individual.ID = str_replace(approx_offsets$Individual.ID, ".wav", "")
annotations = rbind(annotations, approx_offsets[names(annotations)])
annotations = na.omit(annotations)
filtered_annotations = filter(annotations, offset > -60 & Nest.ID == "NNS1")
ggplot(data = filtered_annotations, aes(x=Begin.Time..s., y=offset, color=substr(basename(filename), start = 6, stop = 20))) +
    geom_point() +
    geom_smooth(method = "lm") +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE) +
    labs(color='file datetime')

filtered_annotations = filter(annotations, Nest.ID == "NNBB12")
ggplot(data = filtered_annotations, aes(x=Begin.Time..s., y=offset)) +
    geom_point() +
    geom_smooth(method = "lm") +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE)

ggplot(data = annotations, aes(x=Begin.Time..s., y=offset, color=Nest.ID)) +
    geom_point() +
    geom_smooth(method = "lm") +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE)

Something is wrong with the RFID chip clock - it’s drifting significantly. More data points will help - let’s autodetect PB in the audio files

filtered_annotations = annotations[annotations$Individual.ID == "PB0023" & annotations$Nest.ID == "NNK30",]
print(filtered_annotations[1,])
library(monitoR)
PB23 = makeCorTemplate("clips/PB0023.wav", frq.lim = c(3,10), name="PB0023")

Automatic point selection.

Done.

PB24 = makeCorTemplate("clips/PB0024.wav", frq.lim = c(3,10), name="PB0024")

Automatic point selection.

Done.

ctemps = combineCorTemplates(PB23, PB24)
wav = read_audio(filtered_annotations$Begin.Path[1], from = 300, to = 800)
Error in switch(file_format, wav = read_wav, mp3 = read_mp3, wac = read_wac,  : 
  EXPR must be a length 1 vector

monitoR seems too unreliable for this task, unfortunately

The reason for the drift is SD card write speed. BAR logfiles indicate the true time packed, so if we read the BAR logfiles we can determine the true sampling rate, and correct it. In some cases, it’ll be just under 44.1KHz.

files = list.files("data/2019 BAR recordings", pattern = "logfile.*txt$", recursive = TRUE, full.names=TRUE)
sites = sapply(strsplit(files, "/"), "[[", 4)
df$true_length = rep(NA, nrow(df))
for (site in unique(sites)) {
  files_for_site = files[site == sites]
  lines = unlist(lapply(files_for_site, readLines))
  rec = str_subset(lines, "Recording")
  dt = dmy_hms(str_extract(rec, "^.{19}"))
  rec = rec[order(dt)]
  dt = sort(dt)
  for (i in 1:(length(rec) - 1)) {
    if (str_detect(rec[i], "started") && str_detect(rec[i + 1], "stopped")) {
      filtered_df = df[df$site == site,]
      diffs = time_length(filtered_df$start - dt[i])
      min_i = which.min(abs(diffs))
      min_i = which(df$filename == filtered_df$filename[min_i])
      df$true_length[min_i] = time_length(dt[i+1] - dt[i])
    }
  }
}
ggplot(df[df$site != "KAKA Aviary_20191101_20191113_BAR",], aes(x=start, y=true_length - duration, color = site)) +
  geom_point() + 
  scale_y_continuous(breaks = scales::pretty_breaks(n = 10))

Write out waves with corrected sampling rates

The problem with that though, is that sampling rates in wave files are integers - there’s a loss of precision there. It should be possible to multiply a desired second offset by the true sampling rate and slice a wav file that way.

df$true_sr = df$samples / df$true_length
df$true_sr[!is.na(df$true_sr) & df$true_sr > 44000] = 44100
write.csv(df, "misc/BAR_timespans.csv", row.names = FALSE)
ggplot(df[df$duration > 100,], aes(x=true_sr)) +
  geom_histogram(binwidth=5)

approx_offsets$corrected_offset = sapply(1:nrow(approx_offsets), function(i) {
  approx_offsets$offset[i] * 44100 / df$true_sr[approx_offsets$filename[i] == df$filename]
})
write.csv(approx_offsets, "misc/approx_offsets.csv", row.names = FALSE)
filtered_offsets = approx_offsets[approx_offsets$site == "NNS1" & approx_offsets$filename %in% df$filename[!is.na(df$true_sr)],]
for (i in sample(1:nrow(filtered_offsets), 10)) {
  f = filtered_offsets$filename[i]
  true_sr_for_f = df$true_sr[df$filename == f]
  clip_start = round(filtered_offsets$offset[i] * true_sr_for_f)
  clip_end = round(clip_start + true_sr_for_f)
  print(paste(f, true_sr_for_f, clip_start, clip_end))
  wav = readWave(filename = f, from = clip_start, to = clip_end, units="samples")
  wav@samp.rate = true_sr_for_f
  spectro(wav, main=basename(f), osc=TRUE)
  play(wav)
}
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191201_STUDY [-39.1041 176.8027]/NNS1_20191201_044100_SunriseToSunset [-39.1041 176.8027].wav 44100 261248400 261292500"
play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [    -=|=-    ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [     -|-     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191201_STUDY [-39.1041 176.8027]/NNS1_20191201_064100_SunriseToSunset [-39.1041 176.8027].wav 44100 29061900 29106000"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [ =====|===== ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [     =|=     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191130_STUDY [-39.1041 176.8027]/NNS1_20191130_064100_SunriseToSunset [-39.1041 176.8027].wav 44100 167932800 167976900"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [ -====|====- ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [-=====|=====-]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ] Hd:3.6 Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191202_STUDY [-39.0986 176.8061]/NNS1_20191202_144039_SunriseToSunset [-39.0986 176.8061].wav 43836.3659858274 271566287 271610123"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 87.8k     Bit Rate: 702k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 43836Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:93.4% 00:00:00.93 [00:00:00.07] Out:41.0k [ -====|====- ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [     -|-     ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191202_STUDY [-39.0986 176.8061]/NNS1_20191202_124038_SunriseToSunset [-39.0986 176.8061].wav 43836.3659858274 303873689 303917525"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 87.8k     Bit Rate: 702k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 43836Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:93.4% 00:00:00.93 [00:00:00.07] Out:41.0k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191204_STUDY [-39.0986 176.8061]/NNS1_20191204_084040_SunriseToSunset [-39.0986 176.8061].wav 43830.219844358 136005172 136049002"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 87.7k     Bit Rate: 702k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 43830Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:93.4% 00:00:00.93 [00:00:00.07] Out:41.0k [!=====|=====!]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [  ====|====  ] Hd:0.4 Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ] Hd:0.4 Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191204_STUDY [-39.0986 176.8061]/NNS1_20191204_104040_SunriseToSunset [-39.0986 176.8061].wav 43824.1297762957 138966316 139010140"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 87.7k     Bit Rate: 702k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 43824Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:93.5% 00:00:00.93 [00:00:00.07] Out:41.0k [  -===|===-  ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [    ==|==    ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191204_STUDY [-39.0986 176.8061]/NNS1_20191204_124040_SunriseToSunset [-39.0986 176.8061].wav 43830.3901625677 2147689 2191519"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 87.7k     Bit Rate: 702k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 43830Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:93.4% 00:00:00.93 [00:00:00.07] Out:41.0k [!=====|=====!]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [     =|=     ] Hd:0.0 Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:43.8k [      |      ] Hd:0.0 Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191201_STUDY [-39.1041 176.8027]/NNS1_20191201_044100_SunriseToSunset [-39.1041 176.8027].wav 44100 226806300 226850400"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [   -==|==-   ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [    ==|==    ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191130_STUDY [-39.1041 176.8027]/NNS1_20191130_144100_SunriseToSunset [-39.1041 176.8027].wav 44100 131638500 131682600"

play WARN alsa: can't encode 0-bit Unknown or not applicable

/tmp/RtmpAjDPHN/tuneRtemp.wav:

 File Size: 88.3k     Bit Rate: 706k
  Encoding: Signed PCM    
  Channels: 1 @ 16-bit   
Samplerate: 44100Hz      
Replaygain: off         
  Duration: 00:00:01.00  


In:0.00% 00:00:00.00 [00:00:01.00] Out:0     [      |      ]        Clip:0    
In:92.9% 00:00:00.93 [00:00:00.07] Out:41.0k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
In:100%  00:00:01.00 [00:00:00.00] Out:44.1k [      |      ]        Clip:0    
Done.

annotations$corrected_begin = sapply(1:nrow(annotations), function(i) {
  true_sr = df$true_sr[str_detect(df$base_filename, fixed(annotations$filename[i]))]
  annotations$Begin.Time..s.[i] * 44100 / true_sr
})
annotations$offset = NA
for (i in 1:nrow(annotations)) {
  if (substring(annotations$Individual.ID[i], 0, 2) == "PB") {
    filtered_rfid = filter(rfid, annotations$Nest.ID[i] == site & msg == paste0(annotations$Individual.ID[i], ".wav"))
    matched_rec_start = df$start[str_detect(df$base_filename, fixed(annotations$filename[i]))]
    rfid_offset = time_length(filtered_rfid$datetime - matched_rec_start)
    diffs = time_length(annotations$corrected_begin[i] - rfid_offset)
    min_i = which.min(abs(diffs))
    offset = diffs[min_i]
    if (length(offset) == 1) {
      annotations$offset[i] = offset
    }
  }
}
filtered_annotations = filter(annotations, Nest.ID == "NNS1" & abs(offset) < 60)
ggplot(data = filtered_annotations, aes(x=corrected_begin, y=offset, color=substr(basename(filename), start = 6, stop = 20))) +
    geom_point() +
    geom_smooth(method = "lm") +
    scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
    labs(color='file datetime') +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE) +
    ggtitle("Drift per file at NNS1")

ggplot(data = filtered_annotations, aes(x=datetime, y=offset)) +
    geom_point() +
    geom_smooth(method = "lm") +
    scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
    labs(color='file datetime') +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE) + 
    ggtitle("Drift per day at NNS1")

ggplot(data = annotations, aes(x=corrected_begin, y=offset, color=Nest.ID)) +
    geom_point() +
    geom_smooth(method = "lm") +
    scale_y_continuous(breaks = scales::pretty_breaks(n = 10))

filtered_annotations = filter(annotations, Nest.ID == "NNBB12")
ggplot(data = filtered_annotations, aes(x=datetime, y=offset)) +
    geom_point() +
    geom_smooth(method = "lm") +
    scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
    labs(color='file datetime') +
    stat_poly_eq(formula = y ~ x,
                   aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), 
                   parse = TRUE) + 
    ggtitle("Drift per day at NNBB12")

f = "NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061]"
offset = median(annotations$offset[annotations$filename == f], na.rm=TRUE) # offset for this file
matched_df = df[str_detect(df$base_filename, fixed(f)),]
matched_event_offsets = time_length(rfid$datetime[rfid$msg == "PB0023.wav" & rfid$datetime %within% matched_df$interval & rfid$site == matched_df$site] - matched_df$start)
for (begin_time in matched_event_offsets) {
  sr = matched_df$true_sr
  clip_start = round((begin_time + offset) * sr)
  clip_end = round(clip_start + (sr * 2))
  wav = readWave(matched_df$filename, from = clip_start, to = clip_end, units = "samples")
  print(paste(matched_df$filename, matched_df$true_sr, clip_start, clip_end))
  wav = readWave(filename = matched_df$filename, from = clip_start, to = clip_end, units="samples")
  wav@samp.rate = true_sr_for_f
  spectro(wav, main=begin_time, osc=TRUE)
  #play(wav)
}
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 18526744 18614393"
[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 35749694 35837343"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 53191766 53279415"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 71072080 71159729"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 89127692 89215341"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 106525940 106613589"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 144959852 145047501"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 162577221 162664870"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 179712522 179800171"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 197373716 197461365"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 215516976 215604625"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 232564629 232652278"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 270779420 270867069"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 288090018 288177667"

[1] "data/2019 BAR recordings/NNS DOC Station nests/NNS1/NNS1_20191203_STUDY [-39.0986 176.8061]/NNS1_20191203_064040_SunriseToSunset [-39.0986 176.8061].wav 43824.3009169214 305137672 305225321"

Not bad.

Let’s rename these RFID codes with something a bit more readable. We’ll need to maintain a way of converting between.

unique_rfids = unique(rfid$msg[str_extract(rfid$msg, "^.{2}") == "RF"])
#human_readable_rfids = paste0("bird", 1:length(unique_rfids))
human_readable_rfids = c("alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india", "juliet", "kilo", "lima", "mike", "november")
human_readable_rfids = setNames(human_readable_rfids, unique_rfids)
unique_rfids = setNames(unique_rfids, human_readable_rfids)
processed_rfid = rfid
mask = str_extract(processed_rfid$msg, "^.{2}") == "RF"
processed_rfid$msg[mask] = human_readable_rfids[processed_rfid$msg[mask]]
ggplot(processed_rfid[mask,], aes(x = datetime, color = msg)) +
  geom_freqpoly(binwidth = 60 * 60 * 24) + 
  ggtitle("RFID detections per day")

Try detect entry / exit events by looking at light gate changes

if (file.exists("misc/processed_rfid.csv")) {
  processed_rfid2 = read.csv("misc/processed_rfid.csv")
  processed_rfid2$datetime = ymd_hms(processed_rfid2$datetime)
} else {
  time_threshold = 2
  LG_threshold = 1
  library(pbapply)
  processed_rfid2 = pblapply(1:sum(mask), function(i) {
    dt = processed_rfid$datetime[mask][i]
    this_site = processed_rfid$site[mask][i]
    bird = processed_rfid$msg[mask][i]
    LG = filter(processed_rfid, site == this_site & abs(datetime - dt) < time_threshold & msg == "Light Gate Change")
    if (nrow(LG) > 2) {
      event_type = NULL
      ext_g = mean(diff(LG$ext))
      int_g = mean(diff(LG$int))
      if (ext_g < 0 & int_g > 0) {
        event_type = "entry"
      } else if (int_g < 0 & ext_g > 0) {
        event_type = "exit"
      }
      if (length(event_type) == 1) {
        print(paste(i, bird, event_type, this_site, dt))
        return(data.frame(i = i, bird = bird, event_type = event_type, ext_g = ext_g, int_g = int_g, site = this_site, datetime = dt))
      }
    }
  })
  processed_rfid2 = do.call(rbind, processed_rfid)
  write.csv(processed_rfid2, "misc/processed_rfid.csv", row.names=FALSE)
}
ggplot(processed_rfid2, aes(x = datetime, y = bird, color = event_type)) + geom_point()

ggplot(filter(processed_rfid2, datetime > ymd("2019-12-28") & datetime < ymd("2019-12-29")), aes(x = datetime, y = bird, color = event_type)) + geom_point()

Seems a bit too unreliable - the light gates might be too sensitive. Looks like we’ll have to just slice around RFID passes.

Build a dataframe of datetime intervals to slice - intelligently overlapping for same bird id, and removing intervals where there might be confusion (a playback, or another bird)

Put median offset per file in df

For each interval around a RFID pass, output a wave clip, corrected for offset and SR

df$offset = sapply(df$base_filename, function(f) {
  median(annotations$offset[paste0(annotations$filename) == f], na.rm = TRUE)
})
pblapply(1:nrow(dts_to_slice_deduplicated), function(i) {
  start = dts_to_slice_deduplicated$start[i]
  duration = dts_to_slice_deduplicated$duration[i]
  bird = dts_to_slice_deduplicated$bird[i]
  site = dts_to_slice_deduplicated$site[i]
  matched_df = df[df$site == site & start %within% df$interval & !is.na(df$offset) & !is.na(df$true_sr),]
  if (nrow(matched_df) == 1) {
    sr = matched_df$true_sr
    clip_start_s = time_length(start - matched_df$start) + matched_df$offset
    clip_start_samples = round(clip_start_s * sr)
    clip_end_samples = round(clip_start_samples + (sr * duration))
    #print(paste(i, bird, site, start, duration, matched_df$filename, matched_df$true_sr, clip_start_samples, clip_end_samples))
    wav = readWave(filename = matched_df$filename, from = clip_start_samples, to = clip_end_samples, units="samples")
    wav@samp.rate = sr
    if (sr != 44100) {
      wav = resamp(wav, g = 44100, output = "Wave")
    }
    wav@left = round(wav@left)
    formatted_date = format(start, "%Y-%m-%d_%H%M%S_NZDT")
    output_filename = paste0("data/2019 BAR recordings - individual bird clips/", bird, "/", site, "_", formatted_date, ".wav")
    mkdirs(dirname(output_filename))
    writeWave(wav, filename = output_filename, extensible = F)
  }
})
Error in pblapply(1:nrow(dts_to_slice_deduplicated), function(i) { : 
  could not find function "pblapply"

Use monitoR to remove silence in sliced clips

template_wav = readWave("misc/ZOOM0049_NNK6_LNVX_F_FH_sel.01.ch01.181124.094641.12..wav")
template_wav = resamp(template_wav, g = 44100, output = "Wave")
template_duration = length(template_wav@left) / template_wav@samp.rate
savewav(template_wav, filename = "misc/zip_template.wav")
corTemplate = makeCorTemplate("misc/zip_template.wav", wl = 300, frq.lim = c(5, 15))

Automatic point selection.

Done.

for (bird in human_readable_rfids) {
  files_for_bird = Sys.glob(paste0("data/2019 BAR recordings - individual bird clips/", bird, "/*.wav"))
  clips = c()
  if (length(files_for_bird) == 0) {
    next
  }
  for (i in 1:length(files_for_bird)) {
    f = files_for_bird[i]
    cscores = corMatch(f, corTemplate)
    cdetects = findPeaks(cscores)
    detects = getDetections(cdetects)
    if (i == 1) {
      plot(cdetects)
    }
    if (nrow(detects) > 1) {
      for (j in 1:nrow(detects)) {
        start_time = detects$time[j]
        clip = readWave(f, from = start_time, to = start_time + template_duration, units = "seconds")@left
        clips = c(clips, clip)
      }
    }
  }
  if (length(clips) > 10) {
    wav = Wave(clips, samp.rate = 44100, bit = 16)
    output_filename = paste0("data/2019 BAR recordings - individual bird clips/", bird, ".wav")
    writeWave(wav, output_filename, extensible = F)
  }
}

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done
0 to 10.000022675737 seconds

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done


Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done

Starting  A . . .
    Fourier transform on survey . . .
    Continuing. . .

    Done.

Done with  A
Done
LS0tCnRpdGxlOiAiVGltZSBzeW5jIGNoZWNrIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyBMb2FkIGxpYnJhcmllcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKGMoImJpb2Fjb3VzdGljcyIsICJ0dW5lUiIsICJzZWV3YXZlIiwgImRwbHlyIiwgInRpZHl2ZXJzZSIsICJsdWJyaWRhdGUiLCAidG9vbHMiLCAiZ2dwbG90MiIsICJnZ3BtaXNjIiwgInBsb3RseSIsICJzdHJpbmdyIiwgIm1vbml0b1IiLCAicGJhcHBseSIsICJmb3JlYWNoIiwgImRvUGFyYWxsZWwiLCAiUi51dGlscyIpLCB0eXBlPSJiaW5hcnkiKQpsaWJyYXJ5KGJpb2Fjb3VzdGljcykKbGlicmFyeSh0dW5lUikKbGlicmFyeShzZWV3YXZlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkodG9vbHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3BtaXNjKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGZvcmVhY2gpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShSLnV0aWxzKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShwYmFwcGx5KQp5bWRfaG1zID0gZnVuY3Rpb24oZHQpIHsKICBsdWJyaWRhdGU6OnltZF9obXMoZHQsIHR6PSJQYWNpZmljL0F1Y2tsYW5kIikKfQpkbXlfaG1zID0gZnVuY3Rpb24oZHQpIHsKICBsdWJyaWRhdGU6OmRteV9obXMoZHQsIHR6PSJQYWNpZmljL0F1Y2tsYW5kIikKfQpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCgojIyBMb2FkIFJGSUQgbG9nIGZpbGVzCgpgYGB7cn0KZmlsZXMgPSBsaXN0LmZpbGVzKCJkYXRhLzIwMTkgUkZJRCIsIHBhdHRlcm4gPSAiKi5UWFQkIiwgcmVjdXJzaXZlID0gVFJVRSwgZnVsbC5uYW1lcz1UUlVFKQpjc3ZzID0gbGFwcGx5KGZpbGVzLCBmdW5jdGlvbihwYXRoKSB7CiAgY3N2ID0gcmVhZC5jc3YocGF0aCwgaGVhZGVyPUZBTFNFLCBjb2wubmFtZXMgPSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJob3VyIiwibWludXRlX3NlYyIsICJpZCIsICJleHQiLCAiaW50IiwgIm1zZyIpKQogIGNzdiRzaXRlID0gc3Ryc3BsaXQoc3Ryc3BsaXQocGF0aCwgIi8iKVtbMV1dWzRdLCAiXyIpW1sxXV1bMV0KICBjc3YKfSkKcmZpZCA9IGRvLmNhbGwocmJpbmQsIGNzdnMpCnJmaWQkZGF0ZXRpbWUgPSBwYXN0ZTAocmZpZCR5ZWFyLCAiLSIsIHJmaWQkbW9udGgsICItIiwgcmZpZCRkYXksICIgIiwgcmZpZCRob3VyLCAiOiIsIHJmaWQkbWludXRlX3NlYykKcmZpZCRkYXRldGltZSA9IHltZF9obXMocmZpZCRkYXRldGltZSkKZ2dwbG90KHJmaWQsIGFlcyhkYXRldGltZSkpICsKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gNjAgKiA2MCkKYGBgCiMjIyBSZWZlcmVuY2Ugc3BlY3Ryb2dyYW1zIGZvciBwbGF5YmFjayBmaWxlcwpgYGB7cn0KaHRtbF90YWdfYXVkaW8gPC0gZnVuY3Rpb24oZmlsZSwgdHlwZSA9IGMoIndhdiIpKSB7CiAgdHlwZSA8LSBtYXRjaC5hcmcodHlwZSkKICBodG1sdG9vbHM6OnRhZ3MkaDMoCiAgICBiYXNlbmFtZShmaWxlKSwKICAgIGh0bWx0b29sczo6dGFncyRhdWRpbygKICAgICAgY29udHJvbHMgPSAiIiwKICAgICAgaHRtbHRvb2xzOjp0YWdzJHNvdXJjZSgKICAgICAgICBzcmMgPSBmaWxlLAogICAgICAgIHR5cGUgPSBnbHVlOjpnbHVlKCJhdWRpby97dHlwZX0iLCB0eXBlID0gdHlwZSkKICAgICAgKQogICAgKQogICkKfQpmaWxlcyA9IFN5cy5nbG9iKCIuL2NsaXBzL1BCKi53YXYiKQpQQl93YXZzID0gbGFwcGx5KGZpbGVzLCBmdW5jdGlvbihmKSB7CiAgd2F2ID0gcmVhZF9hdWRpbyhmKQogIHdhdl9sZW5ndGggPSByb3VuZChsZW5ndGgod2F2KSAvIHdhdkBzYW1wLnJhdGUsIDIpCiAgc3BlY3Rybyh3YXYsIG1haW49cGFzdGUwKGJhc2VuYW1lKGYpLCAiICIsIHdhdl9sZW5ndGgsICJzIiksIG9zYz1UUlVFKQogIHByaW50KGh0bWxfdGFnX2F1ZGlvKGYpKQogIGRhdGEuZnJhbWUoZmlsZW5hbWU9YmFzZW5hbWUoZiksIHdhdl9sZW5ndGgpCn0pClBCX3dhdnMgPSBkby5jYWxsKHJiaW5kLCBQQl93YXZzKQpgYGAKCiMjIyBCdWlsZCBhIHJlZmVyZW5jZSBkYXRhZnJhbWUgc2hvd2luZyB3aGljaCB3YXZlIGZpbGVzIGNvcnJlc3BvbmQgdG8gd2hpY2ggdGltZXMKCmBgYHtyfQpyZWFkX0JBUl9tZXRhZGF0YSA9IGZ1bmN0aW9uKGZpbGVzKSB7CiAgbGlicmFyeShwYmFwcGx5KQogIGRmID0gcGJsYXBwbHkoZmlsZXMsIGZ1bmN0aW9uKGYpIHsKICAgIGJpdHMgPSBzdHJzcGxpdChiYXNlbmFtZShmKSwgIl8iKVtbMV1dCiAgICBzdGFydCA9IHltZF9obXMocGFzdGUoYml0c1syXSwgYml0c1szXSkpCiAgICBzaXRlID0gc3Ryc3BsaXQoZiwgIi8iKVtbMV1dWzRdCiAgICB0cnkoewogICAgICB3YXZfaGVhZGVyID0gcmVhZFdhdmUoZiwgaGVhZGVyPVRSVUUpCiAgICAgIGR1cmF0aW9uID0gd2F2X2hlYWRlciRzYW1wbGVzIC8gd2F2X2hlYWRlciRzYW1wbGUucmF0ZQogICAgICBlbmQgPSBzdGFydCArIGR1cmF0aW9uCiAgICAgIHJldHVybihkYXRhLmZyYW1lKGZpbGVuYW1lID0gZiwgYmFzZV9maWxlbmFtZSA9IGJhc2VuYW1lKGYpLCBzaXRlID0gc2l0ZSwgc3RhcnQgPSBzdGFydCwgZW5kID0gZW5kLCBzYW1wbGVzID0gd2F2X2hlYWRlciRzYW1wbGVzLCBzciA9IHdhdl9oZWFkZXIkc2FtcGxlLnJhdGUsIGR1cmF0aW9uPWR1cmF0aW9uLCBpbnRlcnZhbCA9IGludGVydmFsKHN0YXJ0LCBlbmQpKSkKICAgIH0pCiAgICBOVUxMCiAgfSkKICBkZiA9IGRvLmNhbGwocmJpbmQsIGRmKQogIGRmCn0KaWYgKGZpbGUuZXhpc3RzKCJtaXNjL0JBUl90aW1lc3BhbnMuY3N2IikpIHsKICBkZiA9IHJlYWQuY3N2KCJtaXNjL0JBUl90aW1lc3BhbnMuY3N2IikKICBkZiRzdGFydCA9IHltZF9obXMoZGYkc3RhcnQpCiAgZGYkZW5kID0geW1kX2htcyhkZiRlbmQpCiAgZGYkaW50ZXJ2YWwgPSBpbnRlcnZhbChkZiRzdGFydCwgZGYkZW5kKQp9IGVsc2UgewogIGZpbGVzID0gbGlzdC5maWxlcygiZGF0YS8yMDE5IEJBUiByZWNvcmRpbmdzIiwgcGF0dGVybiA9ICIqLndhdiQiLCByZWN1cnNpdmUgPSBUUlVFLCBmdWxsLm5hbWVzPVRSVUUpCiAgZGYgPSByZWFkX0JBUl9tZXRhZGF0YShmaWxlcykKICB3cml0ZS5jc3YoZGYsICJtaXNjL0JBUl90aW1lc3BhbnMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCn0KZGZbYygic2l0ZSIsICJpbnRlcnZhbCIpXQpgYGAKCgojIyMgU2VsZWN0IGEgZmV3IHBsYXliYWNrIGVudHJpZXMgdG8gY2hlY2sKCmBgYHtyfQpQQl90b19jaGVjayA9ICJQQjAwMjMud2F2IgpzaXRlX3RvX2NoZWNrID0gIk5OSzMwIgpmaWx0ZXJlZF9yZmlkID0gZmlsdGVyKHJmaWQsIG1zZyA9PSBQQl90b19jaGVjayAmIHNpdGUgPT0gc2l0ZV90b19jaGVjaykKZmlsdGVyZWRfZGYgPSBmaWx0ZXIoZGYsIHNpdGUgPT0gc2l0ZV90b19jaGVjaykKZmlsdGVyZWRfcmZpZCRjb3JyZWN0ZWRfZGF0ZXRpbWUgPSBmaWx0ZXJlZF9yZmlkJGRhdGV0aW1lCmZpbHRlcmVkX3JmaWQkbWF0Y2ggPSBsYXBwbHkoMTpucm93KGZpbHRlcmVkX3JmaWQpLCBmdW5jdGlvbihpKSB7CiAgZHQgPSBmaWx0ZXJlZF9yZmlkJGNvcnJlY3RlZF9kYXRldGltZVtpXQogIHNpdGUgPSBmaWx0ZXJlZF9yZmlkJHNpdGVbaV0KICBpbmRpY2VzID0gd2hpY2goZHQgJXdpdGhpbiUgZmlsdGVyZWRfZGYkaW50ZXJ2YWwpCiAgaWYgKGxlbmd0aChpbmRpY2VzKSA9PSAwKSBpbmRpY2VzID0gTkEKICBpbmRpY2VzCn0pCnByaW50KHBhc3RlKCJUaGVyZSBhcmUiLCBucm93KGZpbHRlcmVkX3JmaWQpLCBQQl90b19jaGVjaywgInBsYXliYWNrcywgb2Ygd2hpY2giLCBzdW0oIWlzLm5hKGZpbHRlcmVkX3JmaWQkbWF0Y2gpKSwgImhhdmUgcmVjb3JkaW5ncyIpKQojIEEgZmV3IHJhbmRvbWx5CmRhdGV0aW1lc190b19jaGVjayA9IHNvcnQoc2FtcGxlKGZpbHRlcmVkX3JmaWQkY29ycmVjdGVkX2RhdGV0aW1lWyFpcy5uYShmaWx0ZXJlZF9yZmlkJG1hdGNoKV0sIDUpKQojIE9uZXMgZnJvbSB0aGUgMTN0aAojZGF0ZXRpbWVzX3RvX2NoZWNrID0gZmlsdGVyZWRfcmZpZCRjb3JyZWN0ZWRfZGF0ZXRpbWVbIWlzLm5hKGZpbHRlcmVkX3JmaWQkbWF0Y2gpICYgZmlsdGVyZWRfcmZpZCRkYXRldGltZSA+IHltZF9obXMoIjIwMTktMTEtMjAgMDA6MDA6MDAiKSAmIGZpbHRlcmVkX3JmaWQkZGF0ZXRpbWUgPCB5bWRfaG1zKCIyMDE5LTExLTIwIDIzOjU5OjU5IildCiNkYXRldGltZXNfdG9fY2hlY2sgPSBmaWx0ZXJlZF9yZmlkJGNvcnJlY3RlZF9kYXRldGltZVshaXMubmEoZmlsdGVyZWRfcmZpZCRtYXRjaCkgJiBmaWx0ZXJlZF9yZmlkJGNvcnJlY3RlZF9kYXRldGltZSAld2l0aGluJSBpbnRlcnZhbCh5bWRfaG1zKCIyMDE5LTEyLTEzIDE2OjQ1OjAwIiksIHltZF9obXMoIjIwMTktMTItMTMgMTc6MTM6MDAiKSldCnByaW50KGRhdGV0aW1lc190b19jaGVjaykKYGBgCgpgYGB7cn0KI2R0ID0geW1kX2htcygiMjAxOS0xMi0xMyAxNjo0NTowNCIpCnNldFdhdlBsYXllcigicGxheSIpICMgT1MgZGVwZW5kZW50CmNoZWNrZWRfY2xpcHMgPSBsYXBwbHkoZGF0ZXRpbWVzX3RvX2NoZWNrLCBmdW5jdGlvbihkdCkgewogIG1hdGNoID0gZmlsdGVyZWRfcmZpZCRtYXRjaFtmaWx0ZXJlZF9yZmlkJGNvcnJlY3RlZF9kYXRldGltZSA9PSBkdF1bWzFdXQogIGYgPSBmaWx0ZXJlZF9kZiRmaWxlbmFtZVttYXRjaF0KICBjbGlwX3N0YXJ0ID0gdGltZV9sZW5ndGgoZHQgLSBmaWx0ZXJlZF9kZiRzdGFydFttYXRjaF0sIHVuaXQgPSAic2Vjb25kcyIpCiAgY2xpcF9lbmQgPSBjbGlwX3N0YXJ0ICsgMQogIHByaW50KHBhc3RlKGYsIGR0LCBjbGlwX3N0YXJ0LCBjbGlwX2VuZCkpCiAgd2F2ID0gcmVhZF9hdWRpbyhmLCBmcm9tID0gY2xpcF9zdGFydCwgdG8gPSBjbGlwX2VuZCkKICBzcGVjdHJvKHdhdiwgbWFpbj1kdCwgb3NjPVRSVUUpCiAgcGxheSh3YXYpCiAgd2F2Cn0pCmBgYAoKIyMgV3JpdGUgb3V0IGEgY3N2IG9mIGFwcHJveCBwb3NpdGlvbnMgb2YgUEIgZXZlbnRzIHBlciB3YXZlIGZpbGUKCmBgYHtyfQppZiAoZmlsZS5leGlzdHMoIm1pc2MvYXBwcm94X29mZnNldHMuY3N2IikpIHsKICBhcHByb3hfb2Zmc2V0cyA9IHJlYWQuY3N2KCJtaXNjL2FwcHJveF9vZmZzZXRzLmNzdiIpCn0gZWxzZSB7CiAgZmlsdGVyZWRfcmZpZCA9IHJmaWRbc3RyX2V4dHJhY3QocmZpZCRtc2csICJeLnsyfSIpID09ICJQQiIsXQogIGFwcHJveF9vZmZzZXRzID0gbGFwcGx5KDE6bnJvdyhkZiksIGZ1bmN0aW9uKGkpIHsKICAgIG1hdGNoZWRfZXZlbnRzID0gZmlsdGVyZWRfcmZpZFtmaWx0ZXJlZF9yZmlkJHNpdGUgPT0gZGYkc2l0ZVtpXSAmIGZpbHRlcmVkX3JmaWQkZGF0ZXRpbWUgJXdpdGhpbiUgZGYkaW50ZXJ2YWxbaV0sXQogICAgaWYgKG5yb3cobWF0Y2hlZF9ldmVudHMpID09IDApIHsKICAgICAgcmV0dXJuKE5VTEwpCiAgICB9CiAgICBpZiAobnJvdyhtYXRjaGVkX2V2ZW50cykgPiAxMCkgewogICAgICBtYXRjaGVkX2V2ZW50cyA9IHNhbXBsZV9uKG1hdGNoZWRfZXZlbnRzLCAxMCkKICAgIH0KICAgIG9mZnNldHMgPSB0aW1lX2xlbmd0aChtYXRjaGVkX2V2ZW50cyRkYXRldGltZSAtIGRmJHN0YXJ0W2ldKQogICAgZGF0YS5mcmFtZShmaWxlbmFtZSA9IGRmJGZpbGVuYW1lW2ldLCBvZmZzZXQgPSBvZmZzZXRzLCBzaXRlID0gbWF0Y2hlZF9ldmVudHMkc2l0ZSwgcGIgPSBtYXRjaGVkX2V2ZW50cyRtc2csIGRhdGV0aW1lID0gbWF0Y2hlZF9ldmVudHMkZGF0ZXRpbWUpCiAgfSkKICBhcHByb3hfb2Zmc2V0cyA9IGRvLmNhbGwocmJpbmQsIGFwcHJveF9vZmZzZXRzKQogIHdyaXRlLmNzdihhcHByb3hfb2Zmc2V0cywgIm1pc2MvYXBwcm94X29mZnNldHMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCn0KYGBgCgojIyBDb21wYXJlIGFubm90YXRpb25zIHdpdGggbmVhcmVzdCBSRklEIGxvZwoKYGBge3J9CmFubm90YXRpb25zID0gbGFwcGx5KGxpc3QuZmlsZXMoIm1pc2MiLCAiKi50eHQiLCBmdWxsLm5hbWVzPVRSVUUpLCBmdW5jdGlvbihmKSB7CiAgaWYgKHN0cl9kZXRlY3QoZiwgIlpPT00iKSkgewogICAgcmV0dXJuKE5VTEwpCiAgfSBlbHNlIGlmIChzdHJfZGV0ZWN0KGYsICJzZWxlY3Rpb25zIikpIHsKICAgIHggPSByZWFkLnRhYmxlKGYsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSkKICAgIHgkZGF0ZXRpbWUgPSB5bWRfaG1zKHBhc3RlKHgkQmVnaW4uRGF0ZSwgeCRCZWdpbi5DbG9jay5UaW1lKSkKICAgIHggPSB4W2MoIkJlZ2luLlRpbWUuLnMuIiwgIkVuZC5UaW1lLi5zLiIsICJJbmRpdmlkdWFsLklEIiwgIk5lc3QuSUQiLCAiZGF0ZXRpbWUiKV0KICB9IGVsc2UgewogICAgeCA9IHJlYWQudGFibGUoZiwgY29sLm5hbWVzID0gYygiQmVnaW4uVGltZS4ucy4iLCAiRW5kLlRpbWUuLnMuIiwgIkluZGl2aWR1YWwuSUQiKSlbYyhUUlVFLCBGQUxTRSksXQogICAgeCRCZWdpbi5UaW1lLi5zLiA9IGFzLm51bWVyaWMoeCRCZWdpbi5UaW1lLi5zLikKICAgIHgkRW5kLlRpbWUuLnMuID0gYXMubnVtZXJpYyh4JEJlZ2luLlRpbWUuLnMuKQogICAgeCROZXN0LklEID0gc3Ryc3BsaXQoYmFzZW5hbWUoZiksICJfIilbWzFdXVsxXQogICAgeCRkYXRldGltZSA9IGRmJHN0YXJ0W2RmJGJhc2VfZmlsZW5hbWUgPT0gc3RyX3JlcGxhY2UoYmFzZW5hbWUoZiksICIudHh0IiwgIi53YXYiKV0gKyB4JEJlZ2luLlRpbWUuLnMuCiAgfQogIHgkZmlsZW5hbWUgPSBwYXN0ZTAoc3RyX3JlcGxhY2UoYmFzZW5hbWUoZiksICIuQmFuZC5MaW1pdGVkLkVuZXJneS5EZXRlY3Rvci5zZWxlY3Rpb25zLnR4dHwudHh0IiwgIiIpLCAiLndhdiIpCiAgeAp9KQphbm5vdGF0aW9ucyA9IGRvLmNhbGwocmJpbmQsIGFubm90YXRpb25zKQphbm5vdGF0aW9ucyRvZmZzZXQgPSByZXAoTkEsIG5yb3coYW5ub3RhdGlvbnMpKQphbm5vdGF0aW9ucyRJbmRpdmlkdWFsLklEW2Fubm90YXRpb25zJEluZGl2aWR1YWwuSUQgPT0gIlBCMDAwOSIgfCBhbm5vdGF0aW9ucyRJbmRpdmlkdWFsLklEID09ICJQQjAwOSJdID0gIlBCMDAwOXpwIgphbm5vdGF0aW9ucyROZXN0LklEW2Fubm90YXRpb25zJE5lc3QuSUQgPT0gIk5LTjMxIl0gPSAiTk5LMzEiCmZvciAoaSBpbiAxOm5yb3coYW5ub3RhdGlvbnMpKSB7CiAgaWYgKHN1YnN0cmluZyhhbm5vdGF0aW9ucyRJbmRpdmlkdWFsLklEW2ldLCAwLCAyKSA9PSAiUEIiKSB7CiAgICBmaWx0ZXJlZF9yZmlkID0gZmlsdGVyKHJmaWQsIGFubm90YXRpb25zJE5lc3QuSURbaV0gPT0gc2l0ZSAmIG1zZyA9PSBwYXN0ZTAoYW5ub3RhdGlvbnMkSW5kaXZpZHVhbC5JRFtpXSwgIi53YXYiKSkKICAgIG1hdGNoZWRfcmVjX3N0YXJ0ID0gZGYkc3RhcnRbZGYkc2l0ZSA9PSBhbm5vdGF0aW9ucyROZXN0LklEW2ldICYgYW5ub3RhdGlvbnMkZGF0ZXRpbWVbaV0gJXdpdGhpbiUgZGYkaW50ZXJ2YWxdCiAgICBkaWZmcyA9IHRpbWVfbGVuZ3RoKGZpbHRlcmVkX3JmaWQkZGF0ZXRpbWUgLSBhbm5vdGF0aW9ucyRkYXRldGltZVtpXSkKICAgIG1pbl9pID0gd2hpY2gubWluKGFicyhkaWZmcykpCiAgICBvZmZzZXQgPSBkaWZmc1ttaW5faV0KICAgIGlmIChsZW5ndGgob2Zmc2V0KSA9PSAxKSB7CiAgICAgIGFubm90YXRpb25zJG9mZnNldFtpXSA9IG9mZnNldAogICAgfQogIH0KfQoKYXBwcm94X29mZnNldHMgPSByZWFkX2V4Y2VsKCJtaXNjL2FwcHJveF9vZmZzZXRzLnhsc3giKQpuYW1lcyhhcHByb3hfb2Zmc2V0cykgPSBjKCJmaWxlbmFtZSIsICJndWlkZV9zdGFydCIsIE5BLCBOQSwgIkJlZ2luLlRpbWUuLnMuIiwgIk5lc3QuSUQiLCAiSW5kaXZpZHVhbC5JRCIsICJkYXRldGltZSIsIE5BKQphbm5vdGF0aW9ucyA9IHdpdGhpbihhbm5vdGF0aW9ucywgcm0oRW5kLlRpbWUuLnMuKSkKYXBwcm94X29mZnNldHMkb2Zmc2V0ID0gYXBwcm94X29mZnNldHMkZ3VpZGVfc3RhcnQgLSBhcHByb3hfb2Zmc2V0cyRCZWdpbi5UaW1lLi5zLgphcHByb3hfb2Zmc2V0cyRmaWxlbmFtZSA9IGJhc2VuYW1lKGFwcHJveF9vZmZzZXRzJGZpbGVuYW1lKQphcHByb3hfb2Zmc2V0cyRJbmRpdmlkdWFsLklEID0gc3RyX3JlcGxhY2UoYXBwcm94X29mZnNldHMkSW5kaXZpZHVhbC5JRCwgIi53YXYiLCAiIikKYW5ub3RhdGlvbnMgPSByYmluZChhbm5vdGF0aW9ucywgYXBwcm94X29mZnNldHNbbmFtZXMoYW5ub3RhdGlvbnMpXSkKCmFubm90YXRpb25zID0gbmEub21pdChhbm5vdGF0aW9ucykKCmZpbHRlcmVkX2Fubm90YXRpb25zID0gZmlsdGVyKGFubm90YXRpb25zLCBvZmZzZXQgPiAtNjAgJiBOZXN0LklEID09ICJOTlMxIikKZ2dwbG90KGRhdGEgPSBmaWx0ZXJlZF9hbm5vdGF0aW9ucywgYWVzKHg9QmVnaW4uVGltZS4ucy4sIHk9b2Zmc2V0LCBjb2xvcj1zdWJzdHIoYmFzZW5hbWUoZmlsZW5hbWUpLCBzdGFydCA9IDYsIHN0b3AgPSAyMCkpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgc3RhdF9wb2x5X2VxKGZvcm11bGEgPSB5IH4geCwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlKC4uZXEubGFiZWwuLiwgLi5yci5sYWJlbC4uLCBzZXAgPSAifn5+IikpLCAKICAgICAgICAgICAgICAgICAgIHBhcnNlID0gVFJVRSkgKwogICAgbGFicyhjb2xvcj0nZmlsZSBkYXRldGltZScpCmZpbHRlcmVkX2Fubm90YXRpb25zID0gZmlsdGVyKGFubm90YXRpb25zLCBOZXN0LklEID09ICJOTkJCMTIiKQpnZ3Bsb3QoZGF0YSA9IGZpbHRlcmVkX2Fubm90YXRpb25zLCBhZXMoeD1CZWdpbi5UaW1lLi5zLiwgeT1vZmZzZXQpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgc3RhdF9wb2x5X2VxKGZvcm11bGEgPSB5IH4geCwKICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlKC4uZXEubGFiZWwuLiwgLi5yci5sYWJlbC4uLCBzZXAgPSAifn5+IikpLCAKICAgICAgICAgICAgICAgICAgIHBhcnNlID0gVFJVRSkKZ2dwbG90KGRhdGEgPSBhbm5vdGF0aW9ucywgYWVzKHg9QmVnaW4uVGltZS4ucy4sIHk9b2Zmc2V0LCBjb2xvcj1OZXN0LklEKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICAgIHN0YXRfcG9seV9lcShmb3JtdWxhID0geSB+IHgsCiAgICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZSguLmVxLmxhYmVsLi4sIC4ucnIubGFiZWwuLiwgc2VwID0gIn5+fiIpKSwgCiAgICAgICAgICAgICAgICAgICBwYXJzZSA9IFRSVUUpCmBgYAoKU29tZXRoaW5nIGlzIHdyb25nIHdpdGggdGhlIFJGSUQgY2hpcCBjbG9jayAtIGl0J3MgZHJpZnRpbmcgc2lnbmlmaWNhbnRseS4gTW9yZSBkYXRhIHBvaW50cyB3aWxsIGhlbHAgLSBsZXQncyBhdXRvZGV0ZWN0IFBCIGluIHRoZSBhdWRpbyBmaWxlcwoKYGBge3J9CmZpbHRlcmVkX2Fubm90YXRpb25zID0gYW5ub3RhdGlvbnNbYW5ub3RhdGlvbnMkSW5kaXZpZHVhbC5JRCA9PSAiUEIwMDIzIiAmIGFubm90YXRpb25zJE5lc3QuSUQgPT0gIk5OSzMwIixdCnByaW50KGZpbHRlcmVkX2Fubm90YXRpb25zWzEsXSkKbGlicmFyeShtb25pdG9SKQpQQjIzID0gbWFrZUNvclRlbXBsYXRlKCJjbGlwcy9QQjAwMjMud2F2IiwgZnJxLmxpbSA9IGMoMywxMCksIG5hbWU9IlBCMDAyMyIpClBCMjQgPSBtYWtlQ29yVGVtcGxhdGUoImNsaXBzL1BCMDAyNC53YXYiLCBmcnEubGltID0gYygzLDEwKSwgbmFtZT0iUEIwMDI0IikKY3RlbXBzID0gY29tYmluZUNvclRlbXBsYXRlcyhQQjIzLCBQQjI0KQp3YXYgPSByZWFkX2F1ZGlvKGZpbHRlcmVkX2Fubm90YXRpb25zJEJlZ2luLlBhdGhbMV0sIGZyb20gPSAzMDAsIHRvID0gODAwKQpzYXZld2F2KHdhdiwgZmlsZW5hbWU9InRlc3Qud2F2IikKI3NwZWN0cm8od2F2LCBvc2M9VFJVRSkKI3BsYXkod2F2KQpjc2NvcmVzIDwtIGNvck1hdGNoKCJ0ZXN0LndhdiIsIGN0ZW1wcywgcGFyYWxsZWwgPSBUUlVFLCBzaG93LnByb2cgPSBUUlVFKQpjZGV0ZWN0cyA8LSBmaW5kUGVha3MoY3Njb3JlcykKZ2V0RGV0ZWN0aW9ucyhjZGV0ZWN0cykKYGBgCm1vbml0b1Igc2VlbXMgdG9vIHVucmVsaWFibGUgZm9yIHRoaXMgdGFzaywgdW5mb3J0dW5hdGVseQoKClRoZSByZWFzb24gZm9yIHRoZSBkcmlmdCBpcyBTRCBjYXJkIHdyaXRlIHNwZWVkLiBCQVIgbG9nZmlsZXMgaW5kaWNhdGUgdGhlIHRydWUgdGltZSBwYWNrZWQsIHNvIGlmIHdlIHJlYWQgdGhlIEJBUiBsb2dmaWxlcyB3ZSBjYW4gZGV0ZXJtaW5lIHRoZSB0cnVlIHNhbXBsaW5nIHJhdGUsIGFuZCBjb3JyZWN0IGl0LiBJbiBzb21lIGNhc2VzLCBpdCdsbCBiZSBqdXN0IHVuZGVyIDQ0LjFLSHouCgpgYGB7cn0KZmlsZXMgPSBsaXN0LmZpbGVzKCJkYXRhLzIwMTkgQkFSIHJlY29yZGluZ3MiLCBwYXR0ZXJuID0gImxvZ2ZpbGUuKnR4dCQiLCByZWN1cnNpdmUgPSBUUlVFLCBmdWxsLm5hbWVzPVRSVUUpCnNpdGVzID0gc2FwcGx5KHN0cnNwbGl0KGZpbGVzLCAiLyIpLCAiW1siLCA0KQpkZiR0cnVlX2xlbmd0aCA9IHJlcChOQSwgbnJvdyhkZikpCmZvciAoc2l0ZSBpbiB1bmlxdWUoc2l0ZXMpKSB7CiAgZmlsZXNfZm9yX3NpdGUgPSBmaWxlc1tzaXRlID09IHNpdGVzXQogIGxpbmVzID0gdW5saXN0KGxhcHBseShmaWxlc19mb3Jfc2l0ZSwgcmVhZExpbmVzKSkKICByZWMgPSBzdHJfc3Vic2V0KGxpbmVzLCAiUmVjb3JkaW5nIikKICBkdCA9IGRteV9obXMoc3RyX2V4dHJhY3QocmVjLCAiXi57MTl9IikpCiAgcmVjID0gcmVjW29yZGVyKGR0KV0KICBkdCA9IHNvcnQoZHQpCiAgZm9yIChpIGluIDE6KGxlbmd0aChyZWMpIC0gMSkpIHsKICAgIGlmIChzdHJfZGV0ZWN0KHJlY1tpXSwgInN0YXJ0ZWQiKSAmJiBzdHJfZGV0ZWN0KHJlY1tpICsgMV0sICJzdG9wcGVkIikpIHsKICAgICAgZmlsdGVyZWRfZGYgPSBkZltkZiRzaXRlID09IHNpdGUsXQogICAgICBkaWZmcyA9IHRpbWVfbGVuZ3RoKGZpbHRlcmVkX2RmJHN0YXJ0IC0gZHRbaV0pCiAgICAgIG1pbl9pID0gd2hpY2gubWluKGFicyhkaWZmcykpCiAgICAgIG1pbl9pID0gd2hpY2goZGYkZmlsZW5hbWUgPT0gZmlsdGVyZWRfZGYkZmlsZW5hbWVbbWluX2ldKQogICAgICBkZiR0cnVlX2xlbmd0aFttaW5faV0gPSB0aW1lX2xlbmd0aChkdFtpKzFdIC0gZHRbaV0pCiAgICB9CiAgfQp9CmdncGxvdChkZltkZiRzaXRlICE9ICJLQUtBIEF2aWFyeV8yMDE5MTEwMV8yMDE5MTExM19CQVIiLF0sIGFlcyh4PXN0YXJ0LCB5PXRydWVfbGVuZ3RoIC0gZHVyYXRpb24sIGNvbG9yID0gc2l0ZSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSAxMCkpCmBgYAoKIyMgV3JpdGUgb3V0IHdhdmVzIHdpdGggY29ycmVjdGVkIHNhbXBsaW5nIHJhdGVzCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpyZWdpc3RlckRvUGFyYWxsZWwoZGV0ZWN0Q29yZXMoKSAtIDEpCmZpbHRlcmVkX2RmID0gZGZbIWlzLm5hKGRmJHRydWVfbGVuZ3RoKSAmIGRmJHRydWVfbGVuZ3RoID4gMTAwICYgZGYkc2l0ZSAlaW4lIHVuaXF1ZShyZmlkJHNpdGUpLF0KZm9yZWFjaChpID0gMTpucm93KGZpbHRlcmVkX2RmKSwgLnBhY2thZ2VzID0gInR1bmVSIikgICVkb3BhciUgewogIG91dHB1dF9maWxlbmFtZSA9IHN0cl9yZXBsYWNlKGZpbHRlcmVkX2RmJGZpbGVuYW1lW2ldLCAiMjAxOSBCQVIgcmVjb3JkaW5ncyIsICIyMDE5IEJBUiByZWNvcmRpbmdzIC0gZml4ZWQgU1IiKQogIGlmICghZmlsZS5leGlzdHMob3V0cHV0X2ZpbGVuYW1lKSkgewogICAgd2F2ID0gcmVhZFdhdmUoZmlsdGVyZWRfZGYkZmlsZW5hbWVbaV0pCiAgICB3YXZAc2FtcC5yYXRlID0gcm91bmQobGVuZ3RoKHdhdikgLyBmaWx0ZXJlZF9kZiR0cnVlX2xlbmd0aFtpXSkKICAgIG1rZGlycyhkaXJuYW1lKG91dHB1dF9maWxlbmFtZSkpCiAgICB3cml0ZVdhdmUod2F2LCBmaWxlbmFtZSA9IG91dHB1dF9maWxlbmFtZSkKICB9Cn0KYGBgCgpUaGUgcHJvYmxlbSB3aXRoIHRoYXQgdGhvdWdoLCBpcyB0aGF0IHNhbXBsaW5nIHJhdGVzIGluIHdhdmUgZmlsZXMgYXJlIGludGVnZXJzIC0gdGhlcmUncyBhIGxvc3Mgb2YgcHJlY2lzaW9uIHRoZXJlLiBJdCBzaG91bGQgYmUgcG9zc2libGUgdG8gbXVsdGlwbHkgYSBkZXNpcmVkIHNlY29uZCBvZmZzZXQgYnkgdGhlIHRydWUgc2FtcGxpbmcgcmF0ZSBhbmQgc2xpY2UgYSB3YXYgZmlsZSB0aGF0IHdheS4KCmBgYHtyfQpkZiR0cnVlX3NyID0gZGYkc2FtcGxlcyAvIGRmJHRydWVfbGVuZ3RoCmRmJHRydWVfc3JbIWlzLm5hKGRmJHRydWVfc3IpICYgZGYkdHJ1ZV9zciA+IDQ0MDAwXSA9IDQ0MTAwCndyaXRlLmNzdihkZiwgIm1pc2MvQkFSX3RpbWVzcGFucy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKZ2dwbG90KGRmW2RmJGR1cmF0aW9uID4gMTAwLF0sIGFlcyh4PXRydWVfc3IpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9NSkKYGBgCmBgYHtyfQphcHByb3hfb2Zmc2V0cyRjb3JyZWN0ZWRfb2Zmc2V0ID0gc2FwcGx5KDE6bnJvdyhhcHByb3hfb2Zmc2V0cyksIGZ1bmN0aW9uKGkpIHsKICBhcHByb3hfb2Zmc2V0cyRvZmZzZXRbaV0gKiA0NDEwMCAvIGRmJHRydWVfc3JbYXBwcm94X29mZnNldHMkZmlsZW5hbWVbaV0gPT0gZGYkZmlsZW5hbWVdCn0pCndyaXRlLmNzdihhcHByb3hfb2Zmc2V0cywgIm1pc2MvYXBwcm94X29mZnNldHMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKCmBgYHtyfQpmaWx0ZXJlZF9vZmZzZXRzID0gYXBwcm94X29mZnNldHNbYXBwcm94X29mZnNldHMkc2l0ZSA9PSAiTk5TMSIgJiBhcHByb3hfb2Zmc2V0cyRmaWxlbmFtZSAlaW4lIGRmJGZpbGVuYW1lWyFpcy5uYShkZiR0cnVlX3NyKV0sXQpmb3IgKGkgaW4gc2FtcGxlKDE6bnJvdyhmaWx0ZXJlZF9vZmZzZXRzKSwgMTApKSB7CiAgZiA9IGZpbHRlcmVkX29mZnNldHMkZmlsZW5hbWVbaV0KICB0cnVlX3NyX2Zvcl9mID0gZGYkdHJ1ZV9zcltkZiRmaWxlbmFtZSA9PSBmXQogIGNsaXBfc3RhcnQgPSByb3VuZChmaWx0ZXJlZF9vZmZzZXRzJG9mZnNldFtpXSAqIHRydWVfc3JfZm9yX2YpCiAgY2xpcF9lbmQgPSByb3VuZChjbGlwX3N0YXJ0ICsgdHJ1ZV9zcl9mb3JfZikKICBwcmludChwYXN0ZShmLCB0cnVlX3NyX2Zvcl9mLCBjbGlwX3N0YXJ0LCBjbGlwX2VuZCkpCiAgd2F2ID0gcmVhZFdhdmUoZmlsZW5hbWUgPSBmLCBmcm9tID0gY2xpcF9zdGFydCwgdG8gPSBjbGlwX2VuZCwgdW5pdHM9InNhbXBsZXMiKQogIHdhdkBzYW1wLnJhdGUgPSB0cnVlX3NyX2Zvcl9mCiAgc3BlY3Rybyh3YXYsIG1haW49YmFzZW5hbWUoZiksIG9zYz1UUlVFKQogIHBsYXkod2F2KQp9CmBgYAoKYGBge3J9CmFubm90YXRpb25zJGNvcnJlY3RlZF9iZWdpbiA9IHNhcHBseSgxOm5yb3coYW5ub3RhdGlvbnMpLCBmdW5jdGlvbihpKSB7CiAgdHJ1ZV9zciA9IGRmJHRydWVfc3Jbc3RyX2RldGVjdChkZiRiYXNlX2ZpbGVuYW1lLCBmaXhlZChhbm5vdGF0aW9ucyRmaWxlbmFtZVtpXSkpXQogIGFubm90YXRpb25zJEJlZ2luLlRpbWUuLnMuW2ldICogNDQxMDAgLyB0cnVlX3NyCn0pCmFubm90YXRpb25zJG9mZnNldCA9IE5BCmZvciAoaSBpbiAxOm5yb3coYW5ub3RhdGlvbnMpKSB7CiAgaWYgKHN1YnN0cmluZyhhbm5vdGF0aW9ucyRJbmRpdmlkdWFsLklEW2ldLCAwLCAyKSA9PSAiUEIiKSB7CiAgICBmaWx0ZXJlZF9yZmlkID0gZmlsdGVyKHJmaWQsIGFubm90YXRpb25zJE5lc3QuSURbaV0gPT0gc2l0ZSAmIG1zZyA9PSBwYXN0ZTAoYW5ub3RhdGlvbnMkSW5kaXZpZHVhbC5JRFtpXSwgIi53YXYiKSkKICAgIG1hdGNoZWRfcmVjX3N0YXJ0ID0gZGYkc3RhcnRbc3RyX2RldGVjdChkZiRiYXNlX2ZpbGVuYW1lLCBmaXhlZChhbm5vdGF0aW9ucyRmaWxlbmFtZVtpXSkpXQogICAgcmZpZF9vZmZzZXQgPSB0aW1lX2xlbmd0aChmaWx0ZXJlZF9yZmlkJGRhdGV0aW1lIC0gbWF0Y2hlZF9yZWNfc3RhcnQpCiAgICBkaWZmcyA9IHRpbWVfbGVuZ3RoKGFubm90YXRpb25zJGNvcnJlY3RlZF9iZWdpbltpXSAtIHJmaWRfb2Zmc2V0KQogICAgbWluX2kgPSB3aGljaC5taW4oYWJzKGRpZmZzKSkKICAgIG9mZnNldCA9IGRpZmZzW21pbl9pXQogICAgaWYgKGxlbmd0aChvZmZzZXQpID09IDEpIHsKICAgICAgYW5ub3RhdGlvbnMkb2Zmc2V0W2ldID0gb2Zmc2V0CiAgICB9CiAgfQp9CmZpbHRlcmVkX2Fubm90YXRpb25zID0gZmlsdGVyKGFubm90YXRpb25zLCBOZXN0LklEID09ICJOTlMxIiAmIGFicyhvZmZzZXQpIDwgNjApCmdncGxvdChkYXRhID0gZmlsdGVyZWRfYW5ub3RhdGlvbnMsIGFlcyh4PWNvcnJlY3RlZF9iZWdpbiwgeT1vZmZzZXQsIGNvbG9yPXN1YnN0cihiYXNlbmFtZShmaWxlbmFtZSksIHN0YXJ0ID0gNiwgc3RvcCA9IDIwKSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICAgIGxhYnMoY29sb3I9J2ZpbGUgZGF0ZXRpbWUnKSArCiAgICBzdGF0X3BvbHlfZXEoZm9ybXVsYSA9IHkgfiB4LAogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUoLi5lcS5sYWJlbC4uLCAuLnJyLmxhYmVsLi4sIHNlcCA9ICJ+fn4iKSksIAogICAgICAgICAgICAgICAgICAgcGFyc2UgPSBUUlVFKSArCiAgICBnZ3RpdGxlKCJEcmlmdCBwZXIgZmlsZSBhdCBOTlMxIikKCmdncGxvdChkYXRhID0gZmlsdGVyZWRfYW5ub3RhdGlvbnMsIGFlcyh4PWRhdGV0aW1lLCB5PW9mZnNldCkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICAgIGxhYnMoY29sb3I9J2ZpbGUgZGF0ZXRpbWUnKSArCiAgICBzdGF0X3BvbHlfZXEoZm9ybXVsYSA9IHkgfiB4LAogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUoLi5lcS5sYWJlbC4uLCAuLnJyLmxhYmVsLi4sIHNlcCA9ICJ+fn4iKSksIAogICAgICAgICAgICAgICAgICAgcGFyc2UgPSBUUlVFKSArIAogICAgZ2d0aXRsZSgiRHJpZnQgcGVyIGRheSBhdCBOTlMxIikKCmdncGxvdChkYXRhID0gYW5ub3RhdGlvbnMsIGFlcyh4PWNvcnJlY3RlZF9iZWdpbiwgeT1vZmZzZXQsIGNvbG9yPU5lc3QuSUQpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gMTApKQoKZmlsdGVyZWRfYW5ub3RhdGlvbnMgPSBmaWx0ZXIoYW5ub3RhdGlvbnMsIE5lc3QuSUQgPT0gIk5OQkIxMiIpCmdncGxvdChkYXRhID0gZmlsdGVyZWRfYW5ub3RhdGlvbnMsIGFlcyh4PWRhdGV0aW1lLCB5PW9mZnNldCkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICAgIGxhYnMoY29sb3I9J2ZpbGUgZGF0ZXRpbWUnKSArCiAgICBzdGF0X3BvbHlfZXEoZm9ybXVsYSA9IHkgfiB4LAogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUoLi5lcS5sYWJlbC4uLCAuLnJyLmxhYmVsLi4sIHNlcCA9ICJ+fn4iKSksIAogICAgICAgICAgICAgICAgICAgcGFyc2UgPSBUUlVFKSArIAogICAgZ2d0aXRsZSgiRHJpZnQgcGVyIGRheSBhdCBOTkJCMTIiKQpgYGAKCmBgYHtyfQpmID0gIk5OUzFfMjAxOTEyMDNfMDY0MDQwX1N1bnJpc2VUb1N1bnNldCBbLTM5LjA5ODYgMTc2LjgwNjFdIgpvZmZzZXQgPSBtZWRpYW4oYW5ub3RhdGlvbnMkb2Zmc2V0W2Fubm90YXRpb25zJGZpbGVuYW1lID09IGZdLCBuYS5ybT1UUlVFKSAjIG9mZnNldCBmb3IgdGhpcyBmaWxlCm1hdGNoZWRfZGYgPSBkZltzdHJfZGV0ZWN0KGRmJGJhc2VfZmlsZW5hbWUsIGZpeGVkKGYpKSxdCm1hdGNoZWRfZXZlbnRfb2Zmc2V0cyA9IHRpbWVfbGVuZ3RoKHJmaWQkZGF0ZXRpbWVbcmZpZCRtc2cgPT0gIlBCMDAyMy53YXYiICYgcmZpZCRkYXRldGltZSAld2l0aGluJSBtYXRjaGVkX2RmJGludGVydmFsICYgcmZpZCRzaXRlID09IG1hdGNoZWRfZGYkc2l0ZV0gLSBtYXRjaGVkX2RmJHN0YXJ0KQpmb3IgKGJlZ2luX3RpbWUgaW4gbWF0Y2hlZF9ldmVudF9vZmZzZXRzKSB7CiAgc3IgPSBtYXRjaGVkX2RmJHRydWVfc3IKICBjbGlwX3N0YXJ0ID0gcm91bmQoKGJlZ2luX3RpbWUgKyBvZmZzZXQpICogc3IpCiAgY2xpcF9lbmQgPSByb3VuZChjbGlwX3N0YXJ0ICsgKHNyICogMikpCiAgcHJpbnQocGFzdGUobWF0Y2hlZF9kZiRmaWxlbmFtZSwgbWF0Y2hlZF9kZiR0cnVlX3NyLCBjbGlwX3N0YXJ0LCBjbGlwX2VuZCkpCiAgd2F2ID0gcmVhZFdhdmUoZmlsZW5hbWUgPSBtYXRjaGVkX2RmJGZpbGVuYW1lLCBmcm9tID0gY2xpcF9zdGFydCwgdG8gPSBjbGlwX2VuZCwgdW5pdHM9InNhbXBsZXMiKQogIHdhdkBzYW1wLnJhdGUgPSB0cnVlX3NyX2Zvcl9mCiAgc3BlY3Rybyh3YXYsIG1haW49YmVnaW5fdGltZSwgb3NjPVRSVUUpCiAgI3BsYXkod2F2KQp9CmBgYAoKTm90IGJhZC4KCiMjIExldCdzIHJlbmFtZSB0aGVzZSBSRklEIGNvZGVzIHdpdGggc29tZXRoaW5nIGEgYml0IG1vcmUgcmVhZGFibGUuIFdlJ2xsIG5lZWQgdG8gbWFpbnRhaW4gYSB3YXkgb2YgY29udmVydGluZyBiZXR3ZWVuLgoKCmBgYHtyfQp1bmlxdWVfcmZpZHMgPSB1bmlxdWUocmZpZCRtc2dbc3RyX2V4dHJhY3QocmZpZCRtc2csICJeLnsyfSIpID09ICJSRiJdKQojaHVtYW5fcmVhZGFibGVfcmZpZHMgPSBwYXN0ZTAoImJpcmQiLCAxOmxlbmd0aCh1bmlxdWVfcmZpZHMpKQpodW1hbl9yZWFkYWJsZV9yZmlkcyA9IGMoImFscGhhIiwgImJyYXZvIiwgImNoYXJsaWUiLCAiZGVsdGEiLCAiZWNobyIsICJmb3h0cm90IiwgImdvbGYiLCAiaG90ZWwiLCAiaW5kaWEiLCAianVsaWV0IiwgImtpbG8iLCAibGltYSIsICJtaWtlIiwgIm5vdmVtYmVyIikKaHVtYW5fcmVhZGFibGVfcmZpZHMgPSBzZXROYW1lcyhodW1hbl9yZWFkYWJsZV9yZmlkcywgdW5pcXVlX3JmaWRzKQp1bmlxdWVfcmZpZHMgPSBzZXROYW1lcyh1bmlxdWVfcmZpZHMsIGh1bWFuX3JlYWRhYmxlX3JmaWRzKQoKcHJvY2Vzc2VkX3JmaWQgPSByZmlkCm1hc2sgPSBzdHJfZXh0cmFjdChwcm9jZXNzZWRfcmZpZCRtc2csICJeLnsyfSIpID09ICJSRiIKcHJvY2Vzc2VkX3JmaWQkbXNnW21hc2tdID0gaHVtYW5fcmVhZGFibGVfcmZpZHNbcHJvY2Vzc2VkX3JmaWQkbXNnW21hc2tdXQpnZ3Bsb3QocHJvY2Vzc2VkX3JmaWRbbWFzayxdLCBhZXMoeCA9IGRhdGV0aW1lLCBjb2xvciA9IG1zZykpICsKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gNjAgKiA2MCAqIDI0KSArIAogIGdndGl0bGUoIlJGSUQgZGV0ZWN0aW9ucyBwZXIgZGF5IikKYGBgCgojIyBUcnkgZGV0ZWN0IGVudHJ5IC8gZXhpdCBldmVudHMgYnkgbG9va2luZyBhdCBsaWdodCBnYXRlIGNoYW5nZXMKCmBgYHtyfQppZiAoZmlsZS5leGlzdHMoIm1pc2MvcHJvY2Vzc2VkX3JmaWQuY3N2IikpIHsKICBwcm9jZXNzZWRfcmZpZDIgPSByZWFkLmNzdigibWlzYy9wcm9jZXNzZWRfcmZpZC5jc3YiKQogIHByb2Nlc3NlZF9yZmlkMiRkYXRldGltZSA9IHltZF9obXMocHJvY2Vzc2VkX3JmaWQyJGRhdGV0aW1lKQp9IGVsc2UgewogIHRpbWVfdGhyZXNob2xkID0gMgogIExHX3RocmVzaG9sZCA9IDEKICBsaWJyYXJ5KHBiYXBwbHkpCiAgcHJvY2Vzc2VkX3JmaWQyID0gcGJsYXBwbHkoMTpzdW0obWFzayksIGZ1bmN0aW9uKGkpIHsKICAgIGR0ID0gcHJvY2Vzc2VkX3JmaWQkZGF0ZXRpbWVbbWFza11baV0KICAgIHRoaXNfc2l0ZSA9IHByb2Nlc3NlZF9yZmlkJHNpdGVbbWFza11baV0KICAgIGJpcmQgPSBwcm9jZXNzZWRfcmZpZCRtc2dbbWFza11baV0KICAgIExHID0gZmlsdGVyKHByb2Nlc3NlZF9yZmlkLCBzaXRlID09IHRoaXNfc2l0ZSAmIGFicyhkYXRldGltZSAtIGR0KSA8IHRpbWVfdGhyZXNob2xkICYgbXNnID09ICJMaWdodCBHYXRlIENoYW5nZSIpCiAgICBpZiAobnJvdyhMRykgPiAyKSB7CiAgICAgIGV2ZW50X3R5cGUgPSBOVUxMCiAgICAgIGV4dF9nID0gbWVhbihkaWZmKExHJGV4dCkpCiAgICAgIGludF9nID0gbWVhbihkaWZmKExHJGludCkpCiAgICAgIGlmIChleHRfZyA8IDAgJiBpbnRfZyA+IDApIHsKICAgICAgICBldmVudF90eXBlID0gImVudHJ5IgogICAgICB9IGVsc2UgaWYgKGludF9nIDwgMCAmIGV4dF9nID4gMCkgewogICAgICAgIGV2ZW50X3R5cGUgPSAiZXhpdCIKICAgICAgfQogICAgICBpZiAobGVuZ3RoKGV2ZW50X3R5cGUpID09IDEpIHsKICAgICAgICBwcmludChwYXN0ZShpLCBiaXJkLCBldmVudF90eXBlLCB0aGlzX3NpdGUsIGR0KSkKICAgICAgICByZXR1cm4oZGF0YS5mcmFtZShpID0gaSwgYmlyZCA9IGJpcmQsIGV2ZW50X3R5cGUgPSBldmVudF90eXBlLCBleHRfZyA9IGV4dF9nLCBpbnRfZyA9IGludF9nLCBzaXRlID0gdGhpc19zaXRlLCBkYXRldGltZSA9IGR0KSkKICAgICAgfQogICAgfQogIH0pCiAgcHJvY2Vzc2VkX3JmaWQyID0gZG8uY2FsbChyYmluZCwgcHJvY2Vzc2VkX3JmaWQpCiAgd3JpdGUuY3N2KHByb2Nlc3NlZF9yZmlkMiwgIm1pc2MvcHJvY2Vzc2VkX3JmaWQuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQp9CmdncGxvdChwcm9jZXNzZWRfcmZpZDIsIGFlcyh4ID0gZGF0ZXRpbWUsIHkgPSBiaXJkLCBjb2xvciA9IGV2ZW50X3R5cGUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoZmlsdGVyKHByb2Nlc3NlZF9yZmlkMiwgZGF0ZXRpbWUgPiB5bWQoIjIwMTktMTItMjgiKSAmIGRhdGV0aW1lIDwgeW1kKCIyMDE5LTEyLTI5IikpLCBhZXMoeCA9IGRhdGV0aW1lLCB5ID0gYmlyZCwgY29sb3IgPSBldmVudF90eXBlKSkgKyBnZW9tX3BvaW50KCkKYGBgClNlZW1zIGEgYml0IHRvbyB1bnJlbGlhYmxlIC0gdGhlIGxpZ2h0IGdhdGVzIG1pZ2h0IGJlIHRvbyBzZW5zaXRpdmUuIExvb2tzIGxpa2Ugd2UnbGwgaGF2ZSB0byBqdXN0IHNsaWNlIGFyb3VuZCBSRklEIHBhc3Nlcy4KCiMjIEJ1aWxkIGEgZGF0YWZyYW1lIG9mIGRhdGV0aW1lIGludGVydmFscyB0byBzbGljZSAtIGludGVsbGlnZW50bHkgb3ZlcmxhcHBpbmcgZm9yIHNhbWUgYmlyZCBpZCwgYW5kIHJlbW92aW5nIGludGVydmFscyB3aGVyZSB0aGVyZSBtaWdodCBiZSBjb25mdXNpb24gKGEgcGxheWJhY2ssIG9yIGFub3RoZXIgYmlyZCkKCmBgYHtyfQp0aW1lX3RocmVzaG9sZCA9IDUKZXZlbnRzX3RvX2lnbm9yZSA9IGMoIlBvd2VyLW9uIFJlc2V0IiwgIkxvdy12b2x0YWdlIERldGVjdCBSZXNldCIsICJMaWdodCBHYXRlIENoYW5nZSIsIAogICJXYXRjaGRvZyhDT1ApIFJlc2V0IiwgIlBsYXliYWNrIEVycm9yISBSZXN0YXJ0aW5nIiwgIlNvZnR3YXJlIFJlc2V0IgopCgpsaWJyYXJ5KHBiYXBwbHkpCmR0c190b19zbGljZSA9IHBibGFwcGx5KDE6c3VtKG1hc2spLCBmdW5jdGlvbihpKSB7CiAgICBkdCA9IHByb2Nlc3NlZF9yZmlkJGRhdGV0aW1lW21hc2tdW2ldCiAgICB0aGlzX3NpdGUgPSBwcm9jZXNzZWRfcmZpZCRzaXRlW21hc2tdW2ldCiAgICBiaXJkID0gcHJvY2Vzc2VkX3JmaWQkbXNnW21hc2tdW2ldCiAgICB0aGlzX2lkID0gcHJvY2Vzc2VkX3JmaWQkaWRbbWFza11baV0KICAgIAogICAgc3RhcnQgPSBkdCAtIHRpbWVfdGhyZXNob2xkCiAgICBlbmQgPSBkdCArIHRpbWVfdGhyZXNob2xkCiAgICBuZWFyYnlfZXZlbnRzID0gZmlsdGVyKHByb2Nlc3NlZF9yZmlkLCBpZCAhPSB0aGlzX2lkICYgc2l0ZSA9PSB0aGlzX3NpdGUgJiBhYnModGltZV9sZW5ndGgoZGF0ZXRpbWUgLSBkdCkpIDwgdGltZV90aHJlc2hvbGQgJiAhKG1zZyAlaW4lIGV2ZW50c190b19pZ25vcmUpKQogICAgb3RoZXJfYmlyZHMgPSBodW1hbl9yZWFkYWJsZV9yZmlkc1shaHVtYW5fcmVhZGFibGVfcmZpZHMgPT0gYmlyZF0KICAgIGlmIChhbnkob3RoZXJfYmlyZHMgJWluJSBuZWFyYnlfZXZlbnRzJG1zZykpIHsKICAgICAgcHJpbnQocGFzdGUoaSwgImFub3RoZXIgYmlyZCB3aXRoaW4gdGhyZXNob2xkIikpCiAgICAgIHJldHVybihOVUxMKQogICAgfQogICAgaWYgKGFueShzdHJfZXh0cmFjdChuZWFyYnlfZXZlbnRzJG1zZywgIl4uezJ9IikgPT0gIlBCIikpIHsKICAgICAgcHJpbnQocGFzdGUoaSwgInBsYXliYWNrIHdpdGhpbiB0aHJlc2hvbGQiKSkKICAgICAgcmV0dXJuKE5VTEwpCiAgICB9CiAgICBkYXRhLmZyYW1lKGkgPSBpLCBzaXRlID0gdGhpc19zaXRlLCBiaXJkID0gYmlyZCwgc3RhcnQgPSBzdGFydCwgZW5kID0gZW5kLCBpbnRlcnZhbCA9IGludGVydmFsKHN0YXJ0LCBlbmQpKQp9KQpkdHNfdG9fc2xpY2UgPSBkby5jYWxsKHJiaW5kLCBkdHNfdG9fc2xpY2UpCndyaXRlLmNzdihkdHNfdG9fc2xpY2UsICJtaXNjL2R0c190b19zbGljZS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCmR0c190b19zbGljZV9kZWR1cGxpY2F0ZWQgPSBkdHNfdG9fc2xpY2UgJT4lIGdyb3VwX2J5KHNpdGUsIGJpcmQpICU+JSBhcnJhbmdlKHN0YXJ0KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoaW5keCA9IGMoMCwgY3Vtc3VtKGFzLm51bWVyaWMobGVhZChzdGFydCkpID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VtbWF4KGFzLm51bWVyaWMoZW5kKSkpWy1uKCldKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShzaXRlLCBiaXJkLCBpbmR4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShzdGFydCA9IG1pbihzdGFydCksIGVuZCA9IG1heChlbmQpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCgtaW5keCkKZHRzX3RvX3NsaWNlX2RlZHVwbGljYXRlZCRkdXJhdGlvbiA9IHRpbWVfbGVuZ3RoKGR0c190b19zbGljZV9kZWR1cGxpY2F0ZWQkZW5kIC0gZHRzX3RvX3NsaWNlX2RlZHVwbGljYXRlZCRzdGFydCkKd3JpdGUuY3N2KGR0c190b19zbGljZV9kZWR1cGxpY2F0ZWQsICJtaXNjL2R0c190b19zbGljZV9kZWR1cGxpY2F0ZWQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmdncGxvdChkdHNfdG9fc2xpY2VfZGVkdXBsaWNhdGVkLCBhZXMoZHVyYXRpb24pKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkKYGBgCgojIyBQdXQgbWVkaWFuIG9mZnNldCBwZXIgZmlsZSBpbiBkZgojIyBGb3IgZWFjaCBpbnRlcnZhbCBhcm91bmQgYSBSRklEIHBhc3MsIG91dHB1dCBhIHdhdmUgY2xpcCwgY29ycmVjdGVkIGZvciBvZmZzZXQgYW5kIFNSCgpgYGB7cn0KZGYkb2Zmc2V0ID0gc2FwcGx5KGRmJGJhc2VfZmlsZW5hbWUsIGZ1bmN0aW9uKGYpIHsKICBtZWRpYW4oYW5ub3RhdGlvbnMkb2Zmc2V0W3Bhc3RlMChhbm5vdGF0aW9ucyRmaWxlbmFtZSkgPT0gZl0sIG5hLnJtID0gVFJVRSkKfSkKcGJsYXBwbHkoMTpucm93KGR0c190b19zbGljZV9kZWR1cGxpY2F0ZWQpLCBmdW5jdGlvbihpKSB7CiAgc3RhcnQgPSBkdHNfdG9fc2xpY2VfZGVkdXBsaWNhdGVkJHN0YXJ0W2ldCiAgZHVyYXRpb24gPSBkdHNfdG9fc2xpY2VfZGVkdXBsaWNhdGVkJGR1cmF0aW9uW2ldCiAgYmlyZCA9IGR0c190b19zbGljZV9kZWR1cGxpY2F0ZWQkYmlyZFtpXQogIHNpdGUgPSBkdHNfdG9fc2xpY2VfZGVkdXBsaWNhdGVkJHNpdGVbaV0KICBtYXRjaGVkX2RmID0gZGZbZGYkc2l0ZSA9PSBzaXRlICYgc3RhcnQgJXdpdGhpbiUgZGYkaW50ZXJ2YWwgJiAhaXMubmEoZGYkb2Zmc2V0KSAmICFpcy5uYShkZiR0cnVlX3NyKSxdCiAgaWYgKG5yb3cobWF0Y2hlZF9kZikgPT0gMSkgewogICAgc3IgPSBtYXRjaGVkX2RmJHRydWVfc3IKICAgIGNsaXBfc3RhcnRfcyA9IHRpbWVfbGVuZ3RoKHN0YXJ0IC0gbWF0Y2hlZF9kZiRzdGFydCkgKyBtYXRjaGVkX2RmJG9mZnNldAogICAgY2xpcF9zdGFydF9zYW1wbGVzID0gcm91bmQoY2xpcF9zdGFydF9zICogc3IpCiAgICBjbGlwX2VuZF9zYW1wbGVzID0gcm91bmQoY2xpcF9zdGFydF9zYW1wbGVzICsgKHNyICogZHVyYXRpb24pKQogICAgI3ByaW50KHBhc3RlKGksIGJpcmQsIHNpdGUsIHN0YXJ0LCBkdXJhdGlvbiwgbWF0Y2hlZF9kZiRmaWxlbmFtZSwgbWF0Y2hlZF9kZiR0cnVlX3NyLCBjbGlwX3N0YXJ0X3NhbXBsZXMsIGNsaXBfZW5kX3NhbXBsZXMpKQogICAgd2F2ID0gcmVhZFdhdmUoZmlsZW5hbWUgPSBtYXRjaGVkX2RmJGZpbGVuYW1lLCBmcm9tID0gY2xpcF9zdGFydF9zYW1wbGVzLCB0byA9IGNsaXBfZW5kX3NhbXBsZXMsIHVuaXRzPSJzYW1wbGVzIikKICAgIHdhdkBzYW1wLnJhdGUgPSBzcgogICAgaWYgKHNyICE9IDQ0MTAwKSB7CiAgICAgIHdhdiA9IHJlc2FtcCh3YXYsIGcgPSA0NDEwMCwgb3V0cHV0ID0gIldhdmUiKQogICAgfQogICAgd2F2QGxlZnQgPSByb3VuZCh3YXZAbGVmdCkKICAgIGZvcm1hdHRlZF9kYXRlID0gZm9ybWF0KHN0YXJ0LCAiJVktJW0tJWRfJUglTSVTX05aRFQiKQogICAgb3V0cHV0X2ZpbGVuYW1lID0gcGFzdGUwKCJkYXRhLzIwMTkgQkFSIHJlY29yZGluZ3MgLSBpbmRpdmlkdWFsIGJpcmQgY2xpcHMvIiwgYmlyZCwgIi8iLCBzaXRlLCAiXyIsIGZvcm1hdHRlZF9kYXRlLCAiLndhdiIpCiAgICBta2RpcnMoZGlybmFtZShvdXRwdXRfZmlsZW5hbWUpKQogICAgd3JpdGVXYXZlKHdhdiwgZmlsZW5hbWUgPSBvdXRwdXRfZmlsZW5hbWUsIGV4dGVuc2libGUgPSBGKQogIH0KfSkKYGBgCgojIyBVc2UgbW9uaXRvUiB0byByZW1vdmUgc2lsZW5jZSBpbiBzbGljZWQgY2xpcHMKCmBgYHtyfQp0ZW1wbGF0ZV93YXYgPSByZWFkV2F2ZSgibWlzYy9aT09NMDA0OV9OTks2X0xOVlhfRl9GSF9zZWwuMDEuY2gwMS4xODExMjQuMDk0NjQxLjEyLi53YXYiKQp0ZW1wbGF0ZV93YXYgPSByZXNhbXAodGVtcGxhdGVfd2F2LCBnID0gNDQxMDAsIG91dHB1dCA9ICJXYXZlIikKdGVtcGxhdGVfZHVyYXRpb24gPSBsZW5ndGgodGVtcGxhdGVfd2F2QGxlZnQpIC8gdGVtcGxhdGVfd2F2QHNhbXAucmF0ZQpzYXZld2F2KHRlbXBsYXRlX3dhdiwgZmlsZW5hbWUgPSAibWlzYy96aXBfdGVtcGxhdGUud2F2IikKY29yVGVtcGxhdGUgPSBtYWtlQ29yVGVtcGxhdGUoIm1pc2MvemlwX3RlbXBsYXRlLndhdiIsIHdsID0gMzAwLCBmcnEubGltID0gYyg1LCAxNSkpCgpmb3IgKGJpcmQgaW4gaHVtYW5fcmVhZGFibGVfcmZpZHMpIHsKICBmaWxlc19mb3JfYmlyZCA9IFN5cy5nbG9iKHBhc3RlMCgiZGF0YS8yMDE5IEJBUiByZWNvcmRpbmdzIC0gaW5kaXZpZHVhbCBiaXJkIGNsaXBzLyIsIGJpcmQsICIvKi53YXYiKSkKICBjbGlwcyA9IGMoKQogIGlmIChsZW5ndGgoZmlsZXNfZm9yX2JpcmQpID09IDApIHsKICAgIG5leHQKICB9CiAgZm9yIChpIGluIDE6bGVuZ3RoKGZpbGVzX2Zvcl9iaXJkKSkgewogICAgZiA9IGZpbGVzX2Zvcl9iaXJkW2ldCiAgICBjc2NvcmVzID0gY29yTWF0Y2goZiwgY29yVGVtcGxhdGUpCiAgICBjZGV0ZWN0cyA9IGZpbmRQZWFrcyhjc2NvcmVzKQogICAgZGV0ZWN0cyA9IGdldERldGVjdGlvbnMoY2RldGVjdHMpCiAgICBpZiAoaSA9PSAxKSB7CiAgICAgIHBsb3QoY2RldGVjdHMpCiAgICB9CiAgICBpZiAobnJvdyhkZXRlY3RzKSA+IDEpIHsKICAgICAgZm9yIChqIGluIDE6bnJvdyhkZXRlY3RzKSkgewogICAgICAgIHN0YXJ0X3RpbWUgPSBkZXRlY3RzJHRpbWVbal0KICAgICAgICBjbGlwID0gcmVhZFdhdmUoZiwgZnJvbSA9IHN0YXJ0X3RpbWUsIHRvID0gc3RhcnRfdGltZSArIHRlbXBsYXRlX2R1cmF0aW9uLCB1bml0cyA9ICJzZWNvbmRzIilAbGVmdAogICAgICAgIGNsaXBzID0gYyhjbGlwcywgY2xpcCkKICAgICAgfQogICAgfQogIH0KICBpZiAobGVuZ3RoKGNsaXBzKSA+IDEwKSB7CiAgICB3YXYgPSBXYXZlKGNsaXBzLCBzYW1wLnJhdGUgPSA0NDEwMCwgYml0ID0gMTYpCiAgICBvdXRwdXRfZmlsZW5hbWUgPSBwYXN0ZTAoImRhdGEvMjAxOSBCQVIgcmVjb3JkaW5ncyAtIGluZGl2aWR1YWwgYmlyZCBjbGlwcy8iLCBiaXJkLCAiLndhdiIpCiAgICB3cml0ZVdhdmUod2F2LCBvdXRwdXRfZmlsZW5hbWUsIGV4dGVuc2libGUgPSBGKQogIH0KfQpgYGAKCg==